using System.Runtime.CompilerServices;
using UnityEngine;

/// <summary>
/// 单例对象允许重置
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class StaticInstance<T> : MonoBehaviour where T : MonoBehaviour
{
    protected static T _Instance;
    public static T Instance
    {
        get 
        {
            // 同一脚本中，Awake和OnEnable可能同时执行完再去执行另一个脚本中的Awake和OnEnable。存在在OnEnable中获取Instance获取不到的情况
            if (_Instance == null)
            {
                _Instance = FindObjectOfType<T>();
                if(_Instance == null)
                {
#if UNITY_EDITOR
                    Debug.LogError($"can not find {typeof(T).Name} in Hierarchy");
#endif
                }
            }
            return _Instance;
        }
    }

    protected virtual void Awake()
    {
        _Instance = this as T;
    }

    protected virtual void OnApplicationQuit()
    {
        Destroy(gameObject);
    }

    protected virtual void OnDestroy()
    {
        // 在Singleton中会调用Destroy，所以这里需要进行判断
        if(this == _Instance)
        {
            _Instance = null;
        }
    }
}

/// <summary>
/// 单例，切换场景后会被销毁
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class Singleton<T> : StaticInstance<T> where T : MonoBehaviour
{
    protected override void Awake()
    {
        if(_Instance != null && this != Instance)
        {
            // 将新创建的对象删除
            Destroy(gameObject);
            return;
        }
        base.Awake();
    }
}

/// <summary>
/// 常驻节点单例
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class PersistentSingleton<T> : Singleton<T> where T : MonoBehaviour
{
    protected override void Awake()
    {
        base.Awake();
        DontDestroyOnLoad(gameObject);
    }
}

public abstract class NormalSingleton<T> where T : new()
{
    private static T _inst;
    public static T Instance
    {
        get
        {
            if (_inst == null)
            {
                _inst = new T();
            }
            return _inst;
        }
    }
}

public abstract class ASingleton<T> where T : new()
{
    public static T Inst;
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    static ASingleton()
    {
        Inst = new T();
    }
}
